from decorators import Transactional
from enums.menu_app_code_enum import MenuAppCodeEnum
from mauth.login_user_holder import LoginUserHolder
from models.menu import Menu
from models.role_menu import RoleMenu
from services import BaseService
from tools import build_tree, generate_id
from tools.db_tool import DbTool
from sqlalchemy import asc


class MenuService(BaseService):
    """
    菜单模块业务处理类
    """

    def app_list(self):
        """
        应用列表
        """
        res = []
        for member in MenuAppCodeEnum:
            res.append({"label": member.msg, "value": member.name.lower()})
        return res

    def list(self):
        """
        菜单列表
        """
        list = DbTool.filter_by_custom(Menu).order_by(asc(Menu.sort)).all()
        return Menu.to_dict_list(list)

    def tree(self):
        """
        菜单树
        """
        list = DbTool.filter_by_custom(Menu).order_by(asc(Menu.sort)).all()
        return build_tree(Menu.to_dict_list(list))

    @Transactional()
    def sync_route(self, routeList):
        """
        同步路由
        """
        menuIds = []
        if routeList is not None and len(routeList) > 0:
            # 一级菜单
            for route in routeList:
                isSync = route.get("isSync")
                if isSync == 1:
                    menuId = self.save_or_update_route(route, 0)
                    menuIds.append(menuId)
                    # 二级菜单
                    if (
                        route.get("children") is not None
                        and len(route.get("children")) > 0
                    ):
                        for child in route.get("children"):
                            menuId2 = self.save_or_update_route(child, menuId)
                            menuIds.append(menuId2)
                            # 三级菜单
                            if (
                                child.get("children") is not None
                                and len(child.get("children")) > 0
                            ):
                                for grandson in child.get("children"):
                                    menuId3 = self.save_or_update_route(
                                        grandson, menuId2
                                    )
                                    menuIds.append(menuId3)
                                    # 四级菜单
                                    if (
                                        grandson.get("children") is not None
                                        and len(grandson.get("children")) > 0
                                    ):
                                        for greatGrandson in grandson.get("children"):
                                            menuId4 = self.save_or_update_route(
                                                greatGrandson, menuId3
                                            )
                                            menuIds.append(menuId4)
        # 删除前端同步菜单、当前应用、不在当前同步菜单内的路由菜单
        appCode = LoginUserHolder.get_app_code()
        if len(menuIds) == 0:
            menuIds.append(0)
        self.db.session.query(Menu).filter(
            Menu.appCode == appCode, Menu.isSync == 1, Menu.id.notin_(menuIds)
        ).delete()

        sysMenus = (
            self.db.session.query(Menu)
            .filter(Menu.appCode == appCode, Menu.isSync == 1, Menu.id.notin_(menuIds))
            .all()
        )
        if len(sysMenus) > 0:
            deleteMenuIds = [menu.id for menu in sysMenus]
            # 删除冗余菜单
            self.db.session.query(Menu).filter(Menu.id.in_(deleteMenuIds)).delete()
            # 清除角色菜单关联表
            self.db.session.query(RoleMenu).filter(
                RoleMenu.menuId.in_(deleteMenuIds)
            ).delete()

    def save_or_update_route(self, route, pid):
        """
        保存或更新路由
        """
        menu = Menu(**route)
        menu.code = route.get("code")
        menu.appCode = LoginUserHolder.get_app_code()
        menu.parentId = pid
        menu.pids = ""
        if menu.openType is None:
            menu.openType = 0
        newPids = self.create_new_pids(pid)
        menu.pids = newPids
        menu.variable = "{}"
        oldMenu = self.get_menu(menu.code, pid)
        if oldMenu is not None:
            # 存在则更新
            menu.updateUser = LoginUserHolder.get_user_id()
            self.db.session.query(Menu).filter_by(id=oldMenu.id).update(menu.to_dict())
            return oldMenu.id
        else:
            menu.createUser = LoginUserHolder.get_user_id()
            menu.updateUser = LoginUserHolder.get_user_id()
            menu.id = generate_id()
            self.db.session.add(menu)
            return menu.id

    def create_new_pids(self, pid):
        if pid == 0:
            return "[" + str(pid) + "]" + ","
        else:
            # 获取父菜单
            parentMenu = self.db.session.query(Menu).filter_by(id=pid).first()
            if parentMenu is not None:
                print("pids:" + parentMenu.pids)
                return parentMenu.pids + "[" + str(pid) + "]" + ","

    def get_menu(self, code, pid):
        """
        根据code获取菜单
        """
        appCode = LoginUserHolder.get_app_code()
        return (
            self.db.session.query(Menu)
            .filter_by(code=code, parentId=pid, appCode=appCode)
            .first()
        )
